#include "crc.h"
#include "modbus.h"
#include "global.h"
#include "systick.h"
#include "device.h"
#include "device_usart.h"

#define MAX_READ_RW_BIT                952   // 最大读取的RW-bit数量
#define MAX_READ_RO_BIT                984   // 最大读取的RO-bit数量
#define MAX_WRITE_BIT                  952   // 最大写入的RW-bit数量
#define MAX_READ_RW_WORD               61  // 最大读取的RO/RW-WORD数量
#define MAX_READ_RO_WORD               61  // 最大读取的RO/RW-WORD数量
#define MAX_WRITE_WORD                 59  // 最大写入的RW-WORD数量

/*****************************/
//将多字节数转换为小端模式
ushort from_little_endian_16(ushort n)
{
    return (n << 8) | (n >> 8);
}

//将多字节数转换为小端模式
ulong from_little_endian_32(ulong n)
{
    return  (((n << 24) & 0xFF000000) |
             ((n << 16) & 0x00FF0000) |
             ((n >> 16) & 0x0000FF00) |
            (((n >> 24) & 0xFF0000FF)));
}

void No_Response(void)
{
    ++server_no_response_count;
}

void Exception_Response(uchar err)
{
    uchar event;

    // 广播消息不应答
    if (!uart0_buf[0])
    {
        No_Response();
        return;
    }

    uart0_buf[1] |= 0x80;
    uart0_buf[2] = err;
    uart0_len = 3;

    event = EVENT_SENT | (ps_listen_only ? EVENT_LISTEN_ONLY : 0);
    switch(err)
    {
        case ILLEGAL_FUNCTION:
        case ILLEGAL_DATA_ADDRESS:
        case ILLEGAL_DATA_VALUE:
            event |= EVENT_READ_EXCEPTION;
            break;
        case SERVER_DEVICE_FAILURE:
            event |= EVENT_ABORT_EXCEPTION;
            break;
        case ACKNOWLEDGE:
        case SERVER_DEVICE_BUSY:
            event |= EVENT_BUSY_EXCEPTION;
            break;
        default:
            event |= EVENT_EXCEPTION;
            break;
    }

    if (!Uart0_Send_Message())
        event |= EVENT_WRITE_TIMEOUT;

    ++server_exception_count;
    Log_Event(event);
}

void Response(void)
{
    uchar event;
    // 广播消息不应答
    if (!uart0_buf[0])
    {
        No_Response();
        return;
    }

    event = EVENT_SENT | (ps_listen_only ? EVENT_LISTEN_ONLY : 0);
    if (!Uart0_Send_Message())
        event |= EVENT_WRITE_TIMEOUT;

    Log_Event(event); //记录事件
}


// 处理上位机请求
// 数据帧: [地址] [指令] [数据...] [CRC..2byte]
void Process_Request()
{
    uchar addr = uart0_buf[0];
    uchar cmd = uart0_buf[1];
    uchar dataLen = uart0_len - 4;
    uchar n;
    ushort index;
    ushort count;

    if (!uart0_delay_process)
    {
        ++bus_message_count;

        // 超过了最大长度
        if (uart0_len > UART0_BUF_SIZE)
        {
            //++bus_char_overrun_count;
            ++bus_error_count;
            return;
        }

        // 检查数据长度和CRC
        if (uart0_len < 4 || !check_message_crc(uart0_buf, uart0_len))
        {
            ++bus_error_count;
            return;
        }

        // addr = 0: 广播地址
        if (addr && addr != server_address)
        {
            if(uart0_buf[1] & 0x80)
                ++bus_exception_count;
            return;
        }

        ++server_message_count;

        // 记录接收事件
        Log_Event(EVENT_RECEIVED
                  | (addr ? 0 : EVENT_BROADCAST)
                  | (ps_listen_only ? EVENT_LISTEN_ONLY : 0));

        // 只听模式, 只有重启指令执行
        if (ps_listen_only && (cmd != 0x08 || from_little_endian_16(*(short*)&uart0_buf[2]) != 0x01))
        {
            No_Response();
            return;
        }
    }
    uart0_delay_process = 0;

    switch(cmd)
    {
    case 0x01:      // 读RW-bit
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4 || count < 1 || count > MAX_READ_RW_BIT)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_BIT_COUNT || index + count > RW_BIT_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            uart0_len = 2;
            uart0_buf[uart0_len++] = (count+7) >> 3;
            while(count)
            {
                n = count > 8 ? 8 : count;
                uart0_buf[uart0_len++] = Read_RW_bit(index, n);
                index += n;
                count -= n;
            }

            Response();
        }
        break;

    case 0x02:      // 读RO-bit
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4 || count < 1 || count > MAX_READ_RO_BIT)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RO_BIT_COUNT || index + count > RO_BIT_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            uart0_len = 2;
            uart0_buf[uart0_len++] = (count+7) >> 3;
            while(count)
            {
                n = count > 8 ? 8 : count;
                uart0_buf[uart0_len++] = Read_RO_bit(index, n);
                index += n;
                count -= n;
            }

            Response();
        }
        break;

    case 0x03:      // 读RW-word
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4 || count < 1 || count > MAX_READ_RW_WORD)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT || index + count > RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            uart0_len = 2;
            uart0_buf[uart0_len++] = count << 1;
            while(count--)
            {
                *(ushort*)&uart0_buf[uart0_len] = Read_RW_word(index++);
                uart0_len += 2;
            }

            Response();
        }
        break;

    case 0x04:      // 读RO-word
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4 || count < 1 || count > MAX_READ_RO_WORD)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RO_WORD_COUNT || index + count > RO_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            uart0_len = 2;
            uart0_buf[uart0_len++] = count << 1;
            while(count--)
            {
                *(ushort*)&uart0_buf[uart0_len] = Read_RO_word(index++);
                uart0_len += 2;
            }

            Response();
        }
        break;

    case 0x05:      // 写单个RW-bit
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4 || (count != 0x0000 && count != 0xFF00))
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_BIT_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            Write_bit(index, count >> 8, 1);
            uart0_len = 6;
            Response();
        }
        break;

    case 0x06:      // 写单个RW-word
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != 4)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            Write_word(index, count);
            uart0_len = 6;
            Response();
        }
        break;

    case 0x07:      // 读取异常状态
        uart0_buf[2] = Read_Exception();
        uart0_len = 3;
        Response();
        break;

    case 0x08:      // 诊断
        if (dataLen < 2)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else
            Diagnose();
        break;

    case 0x0B:      // 读取事件计数
        n = event_count > MAX_EVENT_COUNT ? MAX_EVENT_COUNT : event_count;
        *(ushort *)&uart0_buf[2] = ps_server_busy ? 0xFFFF : server_status;
        *(ushort *)&uart0_buf[4] = n;
        uart0_len = 6;
        Response();
        break;

    case 0x0C:      // 读取事件记录
        n = event_count > MAX_EVENT_COUNT ? MAX_EVENT_COUNT : event_count;
        uart0_len = 2;
        uart0_buf[uart0_len++] = n + 6;
        *(ushort*)&uart0_buf[uart0_len] = ps_server_busy ? 0xFFFF : server_status;
        uart0_len += 2;
        *(ushort*)&uart0_buf[uart0_len] = n;
        uart0_len += 2;
        *(ushort*)&uart0_buf[uart0_len] = bus_message_count;
        uart0_len += 2;
        for(addr=event_count; n--; --addr)
            uart0_buf[uart0_len++] = event_log[addr & MAX_EVENT_MASK];
        Response();
        break;

    case 0x0F:      // 写多个RW-bit
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != uart0_buf[6] + 5 || count < 1 || count > MAX_WRITE_BIT)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_BIT_COUNT || index + count > RW_BIT_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            addr = 7;
            while(count)
            {
                n = count > 8 ? 8 : count;
                Write_bit(index, uart0_buf[addr++], n);
                count -= n;
                index += n;
            }
            uart0_len = 6;
            Response();
        }
        break;

    case 0x10:      // 写多个RW-word
        index = from_little_endian_16(*(ushort *)&uart0_buf[2]);
        count = from_little_endian_16(*(ushort *)&uart0_buf[4]);

        if (dataLen != uart0_buf[6] + 5 || count < 1 || count > MAX_WRITE_WORD)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT || index + count > RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            n = 7;
            while(count--)
            {
                Write_word(index++, from_little_endian_16(*(ushort*)&uart0_buf[n]));
                n += 2;
            }
            uart0_len = 6;
            Response();
        }
        break;

#if FILE_COUNT
    case 0x14:      // 读文件记录
        addr = uart0_buf[2] / 7;    // 子请求数
        if (dataLen != uart0_buf[2] + 1 || addr > MAX_FILE_REQUEST)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else
        {
            FILE_REQUEST req[MAX_FILE_REQUEST];
            uchar *p = uart0_buf + 3;
            cmd = 0;    // 返回的数据长度

            // 计算请求返回的长度
            for(n = 0; n < addr; ++n, p += 7)
            {
                req[n].fid  = *(ushort*)&p[1] - 1;  // 请求文件号=>索引
                req[n].addr = *(ushort*)&p[3];      // 请求地址
                req[n].len  = *(ushort*)&p[5];      // 请求记录数

                // 检查文件类型和文件号正确性
                if (p[0] != 6 || req[n].fid >= FILE_COUNT)
                {
                    Exception_Response(ILLEGAL_DATA_VALUE);
                    return;
                }

                // 从请求地址处能读取的最大记录数
                count = File_Size(req[n].fid);
                if (req[n].addr >= count)
                    req[n].len = 0;
                else
                {
                    count = count - req[n].addr;
                    if (req[n].len > count)
                        req[n].len = count;
                }

                // 返回数据的长度: 记录数x2 + 应答长度 + 应答类型
                cmd += (req[n].len << 1) + 2;

                // 请求的数据长度超过消息允许的长度
                if (cmd > UART0_BUF_SIZE - 5)
                {
                    Exception_Response(ILLEGAL_DATA_VALUE);
                    return;
                }
            }

            // 开始读取文件请求
            p = &uart0_buf[2];  // 读文件数据
            *p++ = cmd;         // 字节数

            // 所有子请求
            for(n = 0; n < addr; ++n)
            {
                *p++ = (req[n].len << 1) + 1;   // 子请求应答长度
                *p++ = 6;                       // 子请求类型, 必须为6
                while(req[n].len--)
                {
                    *(ushort*)p = Read_File(req[n].fid, req[n].addr++);
                    p += 2;
                }
            }

            uart0_len = p - uart0_buf;
            Response();
        }
        break;

    case 0x15:      // 写文件记录
        if (dataLen != uart0_buf[2] + 1)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else
        {
            // 检验数据正确性
            for (n = 0; n < uart0_buf[2]; )
            {
                if (uart0_buf[n+3] != 6     // 请求类型
                        || *(ushort*)&uart0_buf[n+3+1] - 1 >= FILE_COUNT    // 文件号
                        //|| *(ushort*)&uart0_buf[n+3+3] >=         // 记录号, 根据需要检查
                        )
                {
                    Exception_Response(ILLEGAL_DATA_VALUE);
                    return;
                }

                n += 7 + (*(ushort*)&uart0_buf[n+3+5] << 1);
            }

            // 写入记录
            for (n = 0; n < uart0_buf[2]; )
            {
                addr  = *(ushort*)&uart0_buf[n+3+1] - 1;    // 文件索引号
                index = *(ushort*)&uart0_buf[n+3+3];        // 记录号
                count = *(ushort*)&uart0_buf[n+3+5];        // 记录长度
                n += 7;

                for(; count--; n += 2)
                    Write_File(addr, index++, *(ushort*)&uart0_buf[n+3]);
            }

            // 原样返回
            uart0_len -= 2;
            Response();
        }
        break;
#endif

    case 0x16:      // 掩码写RW-word
        index = *(ushort*)&uart0_buf[2];
        if (dataLen != 6)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);
        else
        {
            count = Read_RW_word(index);
            count &= *(ushort*)&uart0_buf[4];
            count |= ~*(ushort*)&uart0_buf[4] & *(ushort*)&uart0_buf[6];
            Write_word(index, count);
            uart0_len -= 2;
            Response();
        }
        break;

    case 0x17:      // 读/写多个RW-word
        // 检验读操作正确性
        index = *(ushort *)&uart0_buf[2];
        count = *(ushort *)&uart0_buf[4];

        if (count < 1 || count > MAX_READ_RW_WORD)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT || index + count > RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);

        // 检验写操作正确性
        index = *(ushort *)&uart0_buf[6];
        count = *(ushort *)&uart0_buf[8];

        if (dataLen != uart0_buf[10] + 9 || count < 1 || count > MAX_WRITE_WORD - 2)
            Exception_Response(ILLEGAL_DATA_VALUE);
        else if (index >= RW_WORD_COUNT || index + count > RW_WORD_COUNT)
            Exception_Response(ILLEGAL_DATA_ADDRESS);

        // 写寄存器
        for(n = 11; count--; n += 2)
            Write_word(index++, *(ushort*)&uart0_buf[n]);

        // 读寄存器
        index = *(ushort *)&uart0_buf[2];
        count = *(ushort *)&uart0_buf[4];

        // 字节数
        uart0_len = 2;
        uart0_buf[uart0_len++] = count << 1;

        for(; count--; uart0_len += 2)
            *(ushort*)&uart0_buf[uart0_len] = Read_RW_word(index++);

        Response();
        break;

    case 0x2B:      // 传输接口封装
        if (uart0_buf[2] == 0x0E)   // 读取设备标识
            Read_Identification();
#ifdef _USES_UART1
        else if (uart0_buf[2] == 0x0C)
            Modbus_Gateway();
        else if (uart0_buf[2] == 0x0D)
            Modbus_Transparent();
#endif
        else
            Exception_Response(ILLEGAL_DATA_VALUE);
        break;

    default:        // 不支持的指令代码
        Exception_Response(ILLEGAL_FUNCTION);
        break;
    }
}
